package com.example.fence.mqtt;

import com.baomidou.mybatisplus.annotation.IEnum;
import com.example.fence.Task;
import com.example.fence.entity.MyMqttSubClient;
import com.example.fence.enums.AlarmMode;
import com.example.fence.service.MailService;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.DependsOn;
import org.springframework.context.annotation.Lazy;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.stereotype.Component;

import java.time.format.DateTimeFormatter;
import java.util.Set;
import static com.example.fence.util.FenceStoreUtil.*;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;

/**
 * MQTT消息回调方法
 */
@Slf4j
@Component
@DependsOn
public class MqttCallBackHandler implements MqttCallbackExtended {


    private MyMqttSubClient client;



    @Autowired
    @Lazy
    private MailService mailService;


    @Autowired
    @Lazy
    public MqttCallBackHandler(MyMqttSubClient client){
        this.client=client;
    }
    /**
     * 连接成功后调用该方法
     * @param reconnect
     * @param serverURI
     */
    @Override
    public void connectComplete(boolean reconnect, String serverURI) {
        //重新订阅主题
        client.subscribe();
        log.info("=====MQTT重联成功=====");
    }

    /**
     * 断开连接后回调方法
     * @param throwable
     */
    @Override
    public void connectionLost(Throwable throwable) {
        log.error("======MQTT连接断开=====");
    }

    @Override
    public void messageArrived(String topic, MqttMessage message) throws Exception {

        try {
            String IMEI=topic.substring(5,topic.length()-3);
            if(imeiToPointList.containsKey(IMEI)){
                log.info("=====MQTT消息订阅成功=====");
                log.info("主题：" + topic);
                StringBuilder MyData= new StringBuilder();
                //数据转换为16进制
                byte[] dataBytes = message.getPayload();
                for (byte dataByte : dataBytes) {
                    MyData.append(String.format("%02x", dataByte));
                }
                if(topic.contains("B1")){
                    String lat=getLat(MyData.toString());
                    String lon=getLon(MyData.toString());
                    if(lat.equals("NO")||lon.equals("NO")) {
                        log.info(MyData.toString()+IMEI);
                        return;
                    }
                    int inputSwitch =  Integer.parseInt(MyData.toString().substring(44, MyData.length() - 6).substring(52,54),16);
                    System.out.println(inputSwitch);
                    if(( inputSwitch & (1<<6) ) !=0 && ( inputSwitch & (1<<7) ) !=0 )  imeiLock.put(IMEI, true);
                    if(( inputSwitch & (1<<6) ) ==0 && ( inputSwitch & (1<<7) ) ==0 )  imeiLock.put(IMEI, false);
                    System.out.println(imeiLock.get(IMEI));

                    boolean result= Task.decoderTask(topic, MyData.toString());
                    if(!result){
//                       // log.info(MyData.toString());
//                        log.info("lat: "+lat);
//                        log.info("lon: "+lon);
                        //判断报警次数，滤波
                        Integer count = outFenceCounts.get(IMEI);
                        if (count == null) {
                            outFenceCounts.put(IMEI, 1);
                        } else if (count < 4) {
                            outFenceCounts.put(IMEI, count + 1);
                        }
                        else {
                            outFenceCounts.put(IMEI, 0);
                            if(!deviceAlarmMode.containsKey(IMEI)){
                                log.info("IMEI：{}未设置报警",IMEI);
                                return;
                            }
                            Set<Integer> alarmModes = deviceAlarmMode.get(IMEI);
                            log.info("报警类型为：" +alarmModes);
                            //设备出fence后警告的类型 默认断电+发邮件
                            for(Integer num : alarmModes) {
                                AlarmMode alarmMode=AlarmMode.values()[num];
                                switch (alarmMode){
                                    case EMAIL:
                                        try{
                                            if(lastSendTime.containsKey(IMEI)){
                                                if(getMinutesDifference(lastSendTime.get(IMEI),IMEI)){
                                                    mailService.sendSimpleMail(IMEI,lat,lon);
                                                    lastSendTime.put(IMEI,LocalDateTime.now());
                                                }
                                                else log.info("邮件发送时间间隔未到，暂不发送");
                                            }
                                            else {
                                                lastSendTime.put(IMEI, LocalDateTime.now());
                                                mailService.sendSimpleMail(IMEI,lat,lon);
                                                lastSendTime.put(IMEI,LocalDateTime.now());
                                            }
                                        }
                                        catch (Exception e){
                                            log.error("IMEI:{} send emil error ：{}", IMEI,e.toString());
                                        }
                                        break;
                                    case LOCK:
                                        try{
                                            //表中没有或未锁定时
                                            if (!imeiLock.containsKey(IMEI) || !imeiLock.get(IMEI)) {
                                                Task.PostC2(topic);

                                            }
                                            else  if(imeiLock.get(IMEI).equals(true)) log.info("设备已锁定");
                                        }
                                        catch (Exception e){
                                            log.error("IMEI:{} lock error ：{}", IMEI,e.toString());
                                        }

                                        break;
                                    case TEST:
                                        log.info("TESTING.......IMEI:{}",IMEI);
                                        break;
                                    default:
                                        log.error("deviceAlarmMode 不正确{},IMEI:{}",alarmMode,IMEI);
                                        break;
                                }
                            }
                        }
                    }
                    else {
                        if (!imeiLock.containsKey(IMEI) || imeiLock.get(IMEI)) {
                            Task.PostUnC2(topic);
                        }
                        outFenceCounts.put(IMEI, 0);
                    }
                }
            }
        } catch (Exception e){
            e.printStackTrace();
            log.error("message Arrived Exception");
        }
    }
    public boolean getMinutesDifference(LocalDateTime lastTime,String IMEI) {
        LocalDateTime now = LocalDateTime.now();
        return ChronoUnit.MINUTES.between(lastTime, now) > sendInterval.getOrDefault(IMEI, 10);
    }
    public static String getLat(String MyData){
        MyData = MyData.substring(44, MyData.length() - 6);
        int L = Integer.parseInt(MyData.substring(54,56),16);
        int M = Integer.parseInt(MyData.substring(56+4*L,58+4*L),16);
        int N = Integer.parseInt(MyData.substring(58+4*L+2*M,60+4*L+2*M),16);
        int P = Integer.parseInt(MyData.substring(60+4*L+2*M+2*N,62+4*L+2*M+2*N),16);
        //lat
        String lat = MyData.substring(92+4*L+2*M+2*N+2*P,110+4*L+2*M+2*N+2*P);
        //System.out.println(lat);
        StringBuilder sb_lat = new StringBuilder();
        for (int i = 0; i < lat.length(); i += 2) {
            String str_lat = lat.substring(i, i + 2);
            char temp=(char) Integer.parseInt(str_lat, 16);
            if((temp>'9'||temp<'0')&&temp!='.'){
                log.error("lat不合法{}",temp);
                return "NO";
            }
            else  {
                //System.out.println((char) Integer.parseInt(str_lat, 16));
                sb_lat.append((char) Integer.parseInt(str_lat, 16));
            }

        }
        return sb_lat.toString();
    }
    public static void main(String[] args){
        String MyData="eb90008cb10001383639353233303537303034333933196375304e06640cbe050cab001f021e0100001000000010200009140cba0cb30cb60cb20cbe0caf0cb50cb10cb50cb40cb20cac0cb10cad0caf0caf0cb10cad0cb20cab061e1f00000000020000022021010e0006000055ff000059b101454e34352e3735323034343132362e36343830340000000000000836204a003030303030303030303030303030303030303030d7a4fe";
        System.out.println(getLat(MyData));
        System.out.println(getLon(MyData));



    }

    public static String getLon(String MyData){
        MyData = MyData.substring(44, MyData.length() - 6);
        int L = Integer.parseInt(MyData.substring(54,56),16);
        int M = Integer.parseInt(MyData.substring(56+4*L,58+4*L),16);
        int N = Integer.parseInt(MyData.substring(58+4*L+2*M,60+4*L+2*M),16);
        int P = Integer.parseInt(MyData.substring(60+4*L+2*M+2*N,62+4*L+2*M+2*N),16);
        //lon
        String lon = MyData.substring(110+4*L+2*M+2*N+2*P,130+4*L+2*M+2*N+2*P);
        StringBuilder sb_lon = new StringBuilder();
        //System.out.println(lon);
        for (int i = 0; i < lon.length(); i += 2) {
            String str_lon = lon.substring(i, i + 2);
            char temp=(char) Integer.parseInt(str_lon, 16);
            if((temp>'9'||temp<'0')&&temp!='.'){
                log.error("lon不合法{}",temp);
                return "NO";
            }
            else {
                //System.out.println((char) Integer.parseInt(str_lon, 16));
                sb_lon.append((char) Integer.parseInt(str_lon, 16));
            }

        }

        return   sb_lon.toString();
    }



    /**
         * 发送完成
         * @param iMqttDeliveryToken
         */
    @Override
    public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {
        //System.out.println("=====MQTT消息发送完毕=====");
    }
}
